//===========================================================================
// Basic shadow maps support
/////////////////////////////

sampler2D VSGNoiseSampler = sampler_state
{
  Texture = EngineAssets/Textures/noise.dds;
  MinFilter = POINT;
  MagFilter = POINT;
  MipFilter = POINT; 
  AddressU = Wrap;
  AddressV = Wrap;
};

float4 MaterialLayersParamsSG : PI_MaterialLayersParams;//x=frozen, y=wet, z = cloak, w = unuse

///////////////// vertex shader //////////////////
v2f_sh Common_SG_VS(app2vertSGGeneral IN_common)
{
  v2f_sh OUT = (v2f_sh)0; 

  	app2vertSGGeneral IN = IN_common;
#if TEMP_TERRAIN
	IN.vertCommon.Position.z = IN_common.vertCommon.baseTC.x;
#endif

  VSVertexContext vertPassPos = (VSVertexContext)0;
  streamPos_FromSG(IN, vertPassPos);
  
#if TEMP_TERRAIN && _RT_OBJ_IDENTITY
  float4 HPosition = Pos_VS_Terrain(0, g_VS_ViewProjMatr, vertPassPos, true);
#else  
  float4 HPosition = Pos_VS_General(g_VS_ViewProjMatr, vertPassPos, false);
#endif

#if VS_TESSELLATION && !_RT_NO_TESSELLATION
	// For shadow gen this is world position (not relative to camera)
	OUT.vView.xyz = vertPassPos.WorldPos.xyz;
	OUT.vNormal.xyz =  normalize(mul((const float3x3)vertPassPos.InstMatrix, vertPassPos.Normal.xyz));
#endif

	// RSMs
#if (!VS_TESSELLATION || _RT_NO_TESSELLATION) && VS_DRT4
	#if %_RT_DECAL_TEXGEN_2D
		// tex gen for 2d projected decals
		OUT.baseTC.x = dot( DecalTangent, vertPassPos.Position );
		OUT.baseTC.y = dot( DecalBinormal, vertPassPos.Position );  
	#elif TEMP_TERRAIN
		// tex coordinates on the sector textures
		OUT.baseTC.x = dot(float4(0, BaseTCMatrix[0], 0, BaseTCMatrix[1]), vertPassPos.WorldPos);
		OUT.baseTC.y = dot(float4(BaseTCMatrix[0], 0, 0, BaseTCMatrix[2]), vertPassPos.WorldPos);
		OUT.Normal = vertPassPos.Normal;
	#else 
		float3 objSpaceNormal = TangNormalUnnormalized(vertPassPos.Tangent, vertPassPos.Binormal);
		OUT.Normal = mul((float3x3)vertPassPos.InstMatrix, objSpaceNormal);

		// Apply texture modifiers
		float4 baseTC = vertPassPos.baseTC;
		_TCModify(baseTC, baseTC, vertPassPos.Position, OUT.Normal, TS_DIFFUSE);
		OUT.baseTC = baseTC.xy;
	#endif
	OUT.Depth2 = HPosition.zw;
#endif

#if !_RT_CUBEMAP0 
  #if !PS3
  HPosition.z /= GS_VS_FrustrumInfo.y;	//use linear z-buffer
  #endif
  #if !_RT_HW_PCF_COMPARE
    //perspective interpolation is not needed here
    OUT.Depth = HPosition.z - GS_VS_FrustrumInfo.z; //increase precision around camera
  #endif
  #if !PS3
  HPosition.z *= HPosition.w;   //HPosition.z is linearized already
  #endif
#else
  //#if D3D10
  //  HPosition.z += fDepthTestBias.x; //TD: adjust perspective bias 
  //#else
    OUT.Depth = (HPosition.z/GS_VS_FrustrumInfo.y);
    OUT.Depth += fDepthTestBias.x;
  //#endif
//_RT_DIRECTLIGHT
#endif

#if !TEMP_TERRAIN
 #if VS_ALPHATEST || VS_ALPHABLEND || _RT_DISSOLVE
  OUT.baseTC.xy = vertPassPos.baseTC.xy;
 #endif
#endif

#if VS_TESSELLATION && !_RT_NO_TESSELLATION
  OUT.baseTC.xy = vertPassPos.baseTC.xy;
#endif

#if _DS || _PS || !VS_TESSELLATION || _RT_NO_TESSELLATION
  OUT.HPosition = HPosition;
#endif  

  return OUT;
}

// Hull shader and domain shader
#include "CommonShadowGenPassTess.cfi"
//////////////////////////////////////

// Indirect color 
#ifndef D3D10
float4 IndirectColor
<
  psregister = PS_REG_PM_10;
  string UIHelp = "Set the amount of indirectly bounced color"; 
  string UIWidget = "color";

  string UIName = "Indirect bounce color";
> = {0.25, 0.25, 0.25, 0.25};
#else
float4 IndirectColor
<
  psregister = PS_REG_PM_9;
  string UIHelp = "Set the amount of indirectly bounced color"; 
  string UIWidget = "color";

  string UIName = "Indirect bounce color";
> = {0.25, 0.25, 0.25, 0.25};
#endif

#if !TEMP_TERRAIN
half4 AmbientOpPB        : PB_AmbientOpacity;
#endif

struct pixout_shadow
{
  float4 Color  : COLOR0;
#if VS_DRT4
	float4 Depth2  : COLOR1;
  half4 Normal	 : COLOR2;
#endif
#if _RT_HW_PCF_COMPARE && _RT_CUBEMAP0
	#if D3D10
		float Depth		: SV_Depth;
	#else
		float Depth		: DEPTH;
	#endif
#endif
};

///////////////// pixel shader //////////////////
pixout_shadow Common_SG_PS(v2f_sh IN)
{
	pixout_shadow OUT;
	OUT.Color = half4(0,0,0,0);

#if !_RT_HW_PCF_COMPARE
	OUT.Color.rgba = IN.Depth; //FIX: depth output should be here for precision
  #if _RT_VARIANCE_SM
		OUT.Color.g *= IN.Depth; //square for variance shadow maps
  #endif
#else
	#if _RT_CUBEMAP0
		//output linear depth
		OUT.Depth = IN.Depth;
	#endif
#endif

#if (!VS_TESSELLATION || _RT_NO_TESSELLATION) && VS_DRT4
	OUT.Depth2 = IN.Depth2.x / IN.Depth2.y;
	OUT.Normal.xyz = normalize(half3(IN.Normal.xyz))*.5h+.5h;
	OUT.Normal.w = 1;
	#if PS3
		OUT.Depth2 = unpack_4ubyte(OUT.Depth2.x);		// pack it into ARGB8
		OUT.Depth2 = OUT.Depth2.bgra;								// pack it into ARGB8
		OUT.Normal = OUT.Normal.gbar;								// swizzlings for r2vb
	#endif
#endif

#if VS_ALPHATEST || VS_ALPHABLEND || VS_DRT4
	#if !TEMP_TERRAIN
		half4 baseColor = tex2D(diffuseMapSampler, IN.baseTC.xy);
	#else
		half4 baseColor = tex2D(baseMapSampler, IN.baseTC.xy);
	#endif

	#if (_RT_HW_PCF_COMPARE && !D3D10)
		OUT.Color.a = baseColor.a;
	#else
		clip(baseColor.a - PBAlphaTest.w);
	#endif

	#if (!VS_TESSELLATION || _RT_NO_TESSELLATION) && VS_DRT4
		// output RSM color component
		#if !TEMP_TERRAIN
			half3 vFinalIndirectColor = ( MatEmissiveColor.rgb + MatDifColor.rgb ) * IndirectColor.rgb * 4.h; 
			OUT.Color.rgb = baseColor.rgb * vFinalIndirectColor;
		#else
			OUT.Color.rgb = baseColor.rgb;
		#endif
		OUT.Color.a = baseColor.a * AmbientOpPB.w;
	#endif
#endif

#if _RT_DISSOLVE
	#if PS3  // Hack for PS3 bug, cannot disable mipmapping
     		half fNoise = tex2Dlod(VSGNoiseSampler, half4(IN.baseTC.xy*6.h,0,0)).x ;
	#else
     		half fNoise = tex2D(VSGNoiseSampler, IN.baseTC.xy*6.h).x ;
	#endif

      	clip(  fNoise - MaterialLayersParamsSG.z );
#endif
	return OUT;
}

//======================================================================

technique ShadowGen
{
	pass p0
	{
		VertexShader = Common_SG_VS() ShadowGenVS;
#ifdef VS_TESSELLATION
		HullShader   = Common_ShadowGenHS() ShadowGenVS;
		DomainShader = Common_ShadowGenDS() ShadowGenVS;
#endif

		ZEnable = true;
		ZWriteEnable = true;
		CullMode = Back;

		PixelShader = Common_SG_PS() ShadowGenPS;

    #if %GRASS || %LEAVES || %HAIR_PASS || %TEMP_SKIN
      CullMode = None;
    #endif
  }
}
